package com.hsylient.javase.chapter09;

import com.alibaba.fastjson2.JSON;
import com.hsylient.javase.common.enmu.Status;
import com.hsylient.javase.common.entity.Employee;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
public class StreamTest {

    private final List<Employee> employees = Arrays.asList(
            new Employee(1L, "老yy", 73, 74354.32, Status.BUSY),
            new Employee(1L, "老yy", 73, 745424.32, Status.BUSY),
            new Employee(1L, "老yy", 73, 2347454.32, Status.BUSY),
            new Employee(1L, "老yy", 73, 3247454.32, Status.BUSY),
            new Employee(1L, "老yy", 73, 3247454.32, Status.BUSY),
            new Employee(1L, "老yy", 73, 47454.32, Status.BUSY),
            new Employee(1L, "老yy", 73, 7454.32, Status.BUSY),
            new Employee(1L, "老xx", 73, 12.0, Status.BUSY),
            new Employee(1L, "李四", 23, 12.0, Status.FREE),
            new Employee(1L, "王五", 23, 3454.32, Status.VOCATION),
            new Employee(1L, "狗八", 53, 5454.32, Status.FREE),
            new Employee(1L, "琳九", 63, 6454.32, Status.BUSY),
            new Employee(1L, "赵六", 63, 4454.32, Status.FREE),
            new Employee(1L, "老十", 73, 7454.32, Status.VOCATION),
            new Employee(1L, "老zz", 73, 7454.32, Status.BUSY),
            new Employee(1L, "张三", 13, 1454.32, Status.VOCATION)

    );

    /**
     * dropwith 会删除从列表中第一个数据name为老yy的所有数据，如果集合中第一个数据不是老yy那么不能删除任何元素
     */
    @Test
    public void testDropWith() {
        List<Employee> list = employees.stream()
                .dropWhile(x -> Objects.equals(x.getName(), "老yy"))
                .collect(Collectors.toList());
        list.forEach(System.out::println);
    }

    @Test
    public void testFilter() {
        employees.stream()
                .filter(x -> x.getAge() > 35)
                .forEach(System.out::println);
    }


    @Test
    public void testPeek() {
        List<Employee> collect = employees.stream()
                .peek(item -> item.setAge(0))
                .collect(Collectors.toList());
        System.out.println(collect);
    }


    @Test
    public void testLimit() {
        List<Employee> collect = employees.stream()
                .sorted(Comparator.comparingInt(Employee::getAge))
                .limit(2)
                .collect(Collectors.toList());
        collect.forEach(System.out::println);
    }


    @Test
    public void testSkip() {
        List<Employee> collect = employees.stream()
                .sorted(Comparator.comparingInt(Employee::getAge).reversed())
                .skip(3)
                .collect(Collectors.toList());
        collect.forEach(System.out::println);
    }


    @Test
    public void testDistinct() {
        List<Employee> collect = employees.stream()
                .distinct()
                .collect(Collectors.toList());
        System.out.println(collect);
    }

    @Test
    public void test8() {
        List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd", "fff");
        Stream<Stream<Character>> streamStream = list.stream()
                .map(StreamTest::filterCharacter);
        streamStream.forEach(x -> x.forEach(System.out::println));
    }

    // 将字符串转换为字符流
    public static Stream<Character> filterCharacter(String str) {
        List<Character> list = new ArrayList<>();
        for (char c : str.toCharArray()) {
            list.add(c);
        }
        return list.stream();
    }

    /**
     * 对test8进行升级
     * 使用flatMap 接收一个函数作为参数，将流中的每个值转换为另外一个流，然后把所有的流了连成一个流
     */
    @Test
    public void test9() {
        List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd", "fff");
        list.stream()
                .flatMap(StreamTest::filterCharacter)
                .forEach(System.out::println);
    }

    /**
     * 先按年龄 再按姓名
     */
    @Test
    public void testSort() {
        List<Employee> collect = employees.stream()
                .sorted(Comparator.comparingInt(Employee::getAge).thenComparing(Employee::getName))
                .collect(Collectors.toList());
        System.out.println(collect);
    }


    @Test
    public void testAllMatch() {
        boolean b = employees.stream()
                .allMatch(x -> x.getStatus().equals(Status.BUSY));
        System.out.println(b ? "都在忙" : "不是都在忙");
    }

    @Test
    public void testAnyMatch() {
        boolean b = employees.stream()
                .anyMatch(x -> x.getStatus().equals(Status.BUSY));
        System.out.println(b ? "至少有一个在忙" : "都在忙");
    }

    @Test
    public void testNonMatch() {
        boolean b = employees.stream()
                .noneMatch(x -> x.getStatus().equals(Status.BUSY));
        System.out.println(b ? "没有一个在忙" : "有匹配上的元素");
    }

    // 这个是串行流 虽然是随机 但是结果单一
    @Test
    public void test16() {
        Optional<Employee> optionalEmployee = employees.stream()
                .findAny();
        System.out.println(optionalEmployee.get());
    }

    // 并行流
    @Test
    public void test17() {
        Optional<Employee> optionalEmployee = employees.parallelStream()
                .findAny();
        System.out.println(optionalEmployee.get());
    }

    // count用来统计流中元素的数量，而reduce是某个属性的总和
    @Test
    public void test21() {
        List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Integer reduce = integers.stream().reduce(0, Integer::sum);
        System.out.println(reduce);
        long count = integers.stream().distinct().count();
        System.out.println(count);
    }

    @Test
    public void test19() {
        Optional<Employee> max = employees.stream()
                .max(Comparator.comparing(Employee::getAge));
        System.out.println(max.get());
    }

    @Test
    public void test20() {
        employees.stream()
                .min(Comparator.comparing(Employee::getAge))
                .ifPresent(System.out::println);
    }

    // 计算工资的综合
    @Test
    public void test22() {
        Optional<Double> totalSalary = employees.stream()
                .map(Employee::getSalary)
                .reduce(Double::sum);
        System.out.println(totalSalary.get());
    }

    @Test
    public void testStream() {
        List<String> first = List.of("a", "b", "c", "D");
        List<String> second = List.of("A", "B", "C", "D");

        List<String> finalList = Stream.concat(first.stream(), second.stream()).distinct().collect(Collectors.toList());


        log.info("如果在二中没有一，那么就将一的元素加到二中：{}", JSON.toJSONString(finalList));
    }

    @Test
    public void testToMapNPE() {
        Employee employee = new Employee(1L, null, 13, 1454.32, Status.VOCATION);
        Employee employee2 = new Employee(2L, "xx", 13, 1454.32, Status.VOCATION);
        List<Employee> list = List.of(employee, employee2);
        Map<Long, String> collect = list.stream().collect(Collectors.toMap(Employee::getId, Employee::getName));
        System.out.println(collect);
    }
}
